package com.wgo.precise.server.pdf;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;

import remato.domain.common.PropertyDef;
import remato.domain.common.PropertySet;
import remato.domain.common.PropertyValue;
import remato.domain.common.Requirement;
import remato.domain.common.Stakeholder;

import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;

public class RequirementPdfElementFactory extends BasicPdfFactory<Requirement> {
	private static final Logger log = Logger.getLogger(RequirementPdfElementFactory.class);
	private List<String> statuses = new ArrayList<String>();
	private List<String> priorities = new ArrayList<String>();
	
	public RequirementPdfElementFactory(){
		super(Requirement.class.getSimpleName());
		init();
	}
	
	@Override
	public void writeConcept(Requirement requirement, Document doc, int indentation) throws DocumentException {
		PdfPTable table = new PdfPTable(6);
		
		String reqTitle = getReqTitle(requirement);
		PdfPCell titleCell = new PdfPCell(new Paragraph(new Chunk(reqTitle, FontFactory.getFont(FontFactory.HELVETICA_BOLDOBLIQUE, 13, Font.NORMAL))));
		
		titleCell.setColspan(6);
		table.addCell(titleCell);
		
		table.addCell(createLabelCell("Priority"));
		table.addCell(createTextCell(getPriorityString(requirement.getPriority())));
		
		table.addCell(createLabelCell("Status"));
		table.addCell(createTextCell(getStatusString(requirement.getStatus())));
		
		table.addCell(createLabelCell("Version"));
		table.addCell(createTextCell(requirement.getVersion()));
		
		table.addCell(createLabelCell("Category"));
		table.addCell(createTextCell(requirement.getCategory().getName(),2));
		
		table.addCell(createLabelCell("Type"));
		table.addCell(createTextCell(requirement.getCategory().getCategoryParent().getName(),2));
		
		table.addCell(createLabelCell("Date Submitted"));
		SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy hh:mm");
		String submittedDate = "";
		if (null != requirement.getSubmittedDate()) {
			submittedDate = df.format(requirement.getSubmittedDate());
		}
		table.addCell(createTextCell(submittedDate,2));
		
		table.addCell(createLabelCell("Last Update"));
		String updatedDate = "";
		if (null != requirement.getSubmittedDate()) {
			updatedDate = df.format(requirement.getLastUpdatedDate());
		}
		table.addCell(createTextCell(updatedDate,2));
		table.addCell(createLabelCell("Reporter or owner"));
		table.addCell(createTextCell(getName(requirement.getReporterOrOwner()),2));
		
		table.addCell(createLabelCell("Assigned to"));
		table.addCell(createTextCell(getName(requirement.getAssignedTo()),2));
		
		table.addCell(createLabelCell("Stakeholders"));
		String stakeholders = getStakeholders(requirement);
		table.addCell(createTextCell(stakeholders,5));

		table.addCell(createLabelCell("Linked requirements"));
		table.addCell(createTextCell(getLinkedRequirements(requirement),5));
		
		
		table.addCell(createLabelCell("Description_"));
		table.addCell(createTextCell(requirement.getDescription(),5));
		
		if (!requirement.getCategory().getPropertySets().isEmpty()) {
			for (PropertySet propertySet : requirement.getCategory().getPropertySets()) {
				table.addCell(createLabelCell(propertySet.getName(),6));
				for (PropertyDef propertyDef : propertySet.getPropertyDefs()) {
					table.addCell(createLabelCell(propertyDef.getName()));
                    PropertyValue pValue = requirement.getPropertyValue(propertyDef);
                    String propertyVal = (null== pValue) ? "null" : pValue.getValue();
					table.addCell(createTextCell(propertyVal,5));
				}
			}
		}
		
		doc.add(table);
		doc.add(new Paragraph("\n\n"));
	}

	private String getStakeholders(Requirement requirement) {
		StringBuilder sb = new StringBuilder();
		Iterator<Stakeholder> stakeholderIterator = requirement.getStakeholders().iterator();
		while (stakeholderIterator.hasNext()) {
			sb.append(getName(stakeholderIterator.next()));
			if (stakeholderIterator.hasNext()) {
				sb.append(", ");
			}
		}
		String result = sb.toString();
		return result;
	}

	private String getLinkedRequirements(Requirement requirement) {
		StringBuilder sb;
		sb = new StringBuilder();
		Iterator<Requirement> requirementsIterator = requirement.getLinkedToRequirements().iterator();
		while (requirementsIterator.hasNext()) {
			sb.append(getReqTitle(requirementsIterator.next()));
			if (requirementsIterator.hasNext()) {
				sb.append(", ");
			}
		}
		return sb.toString();
	}

	private String getReqTitle(Requirement requirement) {
		String reqName = (null == requirement.getName()) ? "" : requirement.getName();
		String reqTitle = requirement.getBusinessId() + ": " + reqName;
		return reqTitle;
	}
	
	public Class<Requirement> getConceptClass() {
		return Requirement.class;
	}

	private void init(){
        statuses.add("Open");
        statuses.add("Approved");
        statuses.add("Assigned");
        statuses.add("Closed");
        statuses.add("Stopped");
        statuses.add("Merged");
        statuses.add("Reopened");
        priorities.add("Low");
        priorities.add("Medium");
        priorities.add("High");
	}
//	TODO  This should not hardcoded like it is here. The status string should be a part of the status itself, so we can ensure that the status is in sync both on client and server!
	private String getStatusString(int status){
		if (status < 0) {
			log.warn("Invalid status number: " + status + ". The numbers must range between 0 and " + (statuses.size()-1) + ".");
			return null;
		} else if (status > (statuses.size()-1)){
			log.warn("Invalid status number: " + status + ". The numbers must range between 0 and " + (statuses.size()-1) + ".");
			return null;
		}
		return statuses.get(status);
	}
	
//	TODO  This should not hardcoded like it is here. The priority string should be a part of the priority itself, so we can ensure that the priority is in sync both on client and server!
	private String getPriorityString(int priority){
		if (priority < 0) {
			log.warn("Invalid priority number: " + priority + ". The numbers must range between 0 and " + (priorities.size()-1) + ".");
			return null;
		} else if (priority > (priorities.size()-1)){
			log.warn("Invalid priority number: " + priority + ". The numbers must range between 0 and " + (priorities.size()-1) + ".");
			return null;
		}
		return priorities.get(priority);
	}

	private static String getName(Stakeholder sh){
		StringBuilder sb = new StringBuilder("");
		if (null != sh) {
			if (null != sh.getFirstName()) {
				sb.append(sh.getFirstName() + " ");
			}
			if (null != sh.getLastName()) {
				sb.append(sh.getLastName());
			}
		}
		return sb.toString();
	}

}
